package org.gfix.binding;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.PropertyUtils;

class BeanPropertyHierarchy implements Comparable<BeanPropertyHierarchy>
{
	private int depth;
	private String propertyName;
	private Class<?> propertyType;
	private BeanPropertyHierarchy parent;

	BeanPropertyHierarchy(String propertyName, Class<?> propertyType) {
		super();
		this.propertyName = propertyName;
		this.propertyType = propertyType;
	}

	BeanPropertyHierarchy(String propertyName, Class<?> propertyType,
			BeanPropertyHierarchy parent) {
		super();
		this.propertyName = propertyName;
		this.propertyType = propertyType;
		this.parent = parent;
		this.depth = parent.depth +1;
	}

	
	@Override
	public int compareTo(BeanPropertyHierarchy o)
	{
		if(this.depth< o.depth)
		{
			return 1;
		}
		else if(this.depth > o.depth)
		{
			return -1;
		}
		else
		{
			return this.propertyName.compareTo(o.propertyName);
		}
	}

	public Object getBeanNoCreate(Object from) throws IllegalAccessException, 
	InvocationTargetException, NoSuchMethodException
	{
		if(propertyName.length() == 0)
		{
			return from;
		}
		Object source = parent.getBeanNoCreate(from);
		if(source != null)
		{
			source = PropertyUtils.getProperty(source,propertyName);
		}
		return source;
	}

	public Object getBean(FixBindingContext from) throws IllegalAccessException, 
		InvocationTargetException, NoSuchMethodException, 
		InstantiationException
	{
		if(propertyName.length() == 0 && from.getBoundObject() != null)
		{
			return from.getBoundObject();
		}
		else if(from.getBoundObject() == null)
		{
			from.setBoundObject( propertyType.newInstance());
			return from.getBoundObject();			
		}
		return traverseTree(from.getBoundObject());
	}
	
	private Object traverseTree(Object from)throws IllegalAccessException, 
				InvocationTargetException, NoSuchMethodException, 
				InstantiationException
	{
		if(parent == null)
		{
			return from;
		}
		Object source = parent.traverseTree(from);
		Object reference = PropertyUtils.getProperty(source,propertyName);
		if(reference == null)
		{
			reference = propertyType.newInstance();
			PropertyUtils.setProperty(source, propertyName, reference);
		}
		return reference;
	}
	
}